﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using LightCAD.Three;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LightCAD.Runtime
{
    public abstract class ElementAction: ICreateDrawer
    {
        public static class SR
        {
            public const string PointError = "需要点或选项关键字。";

        }
        public static Stack<LcBlockRef> RefStack { get; } = new Stack<LcBlockRef>();

        public SKPaint GetDrawPen(LcElement element, bool isDragCopy=false)
        {
            if(element.RtStatus == ElementStatus.Disabled)
            {
                return Constants.disabledPen;
            }

            if (this.vportRt.IsRefEditing)
            {
                //只有在位编辑的引用对象才会正常显示，其他的都显示为Disabled
                var refObj = this.vportRt.RefEditingObject;
                foreach(var blkRef in RefStack)
                {
                    if(blkRef != refObj.Target)
                    {
                        return Constants.disabledPen;
                    }
                }
            }

            if (isDragCopy) return Constants.defaultPen;

            if (element.RtStatus == ElementStatus.Dragging)
            {
                return Constants.draggingPen;
            }
            else if (element.IsSelected)
            {
                return Constants.selectedPen;
            }
            else
            {
                return Constants.defaultPen;
            }
        }

        protected CancellationTokenSource cts;
        protected bool isFinish;
        protected DocumentRuntime docRt;
        protected ViewportRuntime vportRt;
        protected ElementAction(DocumentRuntime docRt)
        {
            this.docRt = docRt;
            this.vportRt = docRt.DrawingEditRt.ActiveViewportRt;
            if (this.vportRt == null)
            {

            }
        }
        protected ElementAction()
        {
        }

        public ElementAction SetViewport(ViewportRuntime vportRt)
        {
            this.vportRt = vportRt;
            this.docRt = vportRt.docRt;
            return this;
        }
        protected void AttachEvents()
        {
            //docRt.ActiveViewportRt.Control.AttachEvents(this.OnViewportMouseEvent, this.OnViewportKeyDown);
            //docRt.Commander.AttachInputEvent(OnInputKeyDown, OnInputKeyUp);
        }



        protected void DetachEvents()
        {
            //docRt.ActiveViewportRt.Control.DetachEvents(this.OnViewportMouseEvent, this.OnViewportKeyDown);
            //docRt.Commander.DetachInputEvent(OnInputKeyDown, OnInputKeyUp);
        }
        protected async Task WaitFinish()
        {
            cts = new CancellationTokenSource();
            await Task.Run(() =>
            {
                while (!cts.Token.IsCancellationRequested && !isFinish) { }
            }, cts.Token);
        }
        protected virtual void OnViewportMouseEvent(string type, MouseEventRuntime e)
        {
        }
        protected virtual void OnViewportKeyDown(KeyEventRuntime e)
        {
        }
        protected virtual void OnInputKeyDown(KeyEventRuntime e)
        {
        }
        protected virtual void OnInputKeyUp(KeyEventRuntime e)
        {
        }

        public void StartCreating()
        {
            var vportRt = this.docRt.DrawingEditRt.ActiveViewportRt;
            if (vportRt.CheckStatus(ViewportStatus.InAction))
            {
                vportRt.CancelCurrentAction();
            }
            vportRt.CurrentAction = this;
            vportRt.SetStatus(ViewportStatus.InAction);
            CommandCenter.Instance.InAction = true;
            this.vportRt.SetCreateDrawer(this);//设置绘制辅助线等

        }
        public void EndCreating()
        {
            var vportRt = this.docRt.DrawingEditRt.ActiveViewportRt;
            vportRt.ClearStatus();
            this.vportRt.SetCreateDrawer(null);
            this.vportRt.docRt.CommandCtrl.Prompt(string.Empty);
            this.vportRt.CurrentAction = null;
            this.vportRt.CursorType = LcCursorType.SelectElement;
            this.vportRt.CursorAddon = CursorAddonType.None;
            CommandCenter.Instance.InAction = false;
            this.vportRt.CancelCurrentAction();
            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.docRt.Action.SetSelectsToDragging(false);
                this.docRt.Action.ClearElementGrips();
                this.docRt.Action.ClearSelects();
            }
            //DocumentManager.Recorders.Add(this.)
            //if (IsStopRecord) return;
            //if (this.CurrentActionName == null)
            //{
            //    throw new InvalidOperationException("CurrentActionIsNull");
            //}
            //ClearRecordsFromIndx();//将索引点后面的记录清除
            //this.CurrentActionRecord.EndTime = DateTime.Now;
            //this.Records.Add(this.CurrentActionRecord);
            //this.CurrentRecordIndex++;
            //this.CurrentActionRecord = null;
            //this.CurrentActionName = null;
        }

        public virtual void DrawAuxLines(SKCanvas canvas)
        {

        }
        public virtual void DrawTemp(SKCanvas canvas)
        {
        }
        public virtual void CreateElement(LcElement element, Matrix3d matrix)
        {

        }
        public virtual void CreateElement(LcElement element, Vector2d basePoint, double scaleFactor)
        {

        }
        public virtual void CreateElement(LcElement element, Vector2d basePoint, Vector2d scaleVector)
        {

        }


        /// <summary>
        /// 在指定的Cavas上绘制指定的元素,2D
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="element"></param>
        /// <param name="offset"></param>
        public virtual void Draw(SKCanvas canvas, LcElement element, Vector2d offset)
        {
            this.Draw(canvas, element, Matrix3d.Translate(offset));
        }
        /// <summary>
        /// 在指定的Cavas上绘制指定的元素,3D
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="element"></param>
        /// <param name="matrix"></param>
        public virtual void Draw(SKCanvas canvas, LcElement element, Matrix3d matrix)
        {

        }
        public virtual void Cancel()
        {
            this.DetachEvents();
        }
        /// <summary>
        /// 获取元素的控制点(夹点)
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public virtual ControlGrip[] GetControlGrips(LcElement element)
        {
            return null;
        }

        /// <summary>
        /// 设置拖拽控制柄状态
        /// </summary>
        /// <param name="element">拖拽的元素</param>
        /// <param name="gripName">控制柄名称，不同名称有不同处理方法</param>
        /// <param name="position">控制点的当前拖拽位置</param>
        /// <param name="isEnd">是否拖拽结束</param>
        public virtual void SetDragGrip(LcElement element, string gripName, Vector2d position, bool isEnd) { }

        /// <summary>
        /// 绘制拖拽控制点的线条
        /// </summary>
        /// <param name="canvas"></param>
        public virtual void DrawDragGrip(SKCanvas canvas) { }


        public virtual BufferGeometry[] CreateGeometry3D(LcElement element, Matrix3d matrix)
        {
            return null;
        }

        public virtual List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>();
        }

        private static List<PropertyObserver> _sharedPropertyObservers;
     
        
        /// <summary>
        /// 返回共享的属性观察者(监视器)
        /// </summary>
        /// <returns></returns>
        public static List<PropertyObserver> GetSharedPropertyObservers()
        {
            if (_sharedPropertyObservers != null)
            {
                return _sharedPropertyObservers;
            }

            _sharedPropertyObservers = new List<PropertyObserver>()
            {
                new PropertyObserver()
                {
                    Name = "Color",
                    DisplayName = "颜色",
                    Getter = (ele) => ele.Color,
                    Setter = (ele, value) => { ele.Color = (string)value; }
                },
                new PropertyObserver()
                {
                    Name = "Layer",
                    DisplayName = "图层",
                    Getter = (ele) => ele.Layer,
                    Setter = (ele, value) => { ele.Layer = (string)value; }
                },
                new PropertyObserver()
                {
                    Name = "LineType",
                    DisplayName = "线型",
                    Getter = (ele) => ele.LineType,
                    Setter = (ele, value) => { ele.LineType = (string)value; }
                },
                new PropertyObserver()
                {
                    Name = "LineTypeScale",
                    DisplayName = "线型比例",
                    Getter = (ele) => ele.LineTypeScale,
                    Setter = (ele, value) => { ele.LineTypeScale = (double)value; }
                },
                new PropertyObserver()
                {
                    Name = "LineWeight",
                    DisplayName = "线宽",
                    Getter = (ele) => ele.LineWeight,
                    Setter = (ele, value) => { ele.LineWeight = (string)value; }
                },
                new PropertyObserver()
                {
                    Name = "PlotStyleName",
                    DisplayName = "打印样式",
                    Getter = (ele) => ele.PlotStyleName,
                    Setter = (ele, value) => { ele.PlotStyleName = (string)value; }
                },
                new PropertyObserver()
                {
                    Name = "Transparency",
                    DisplayName = "透明度",
                    Getter = (ele) => ele.Transparency,
                    Setter = (ele, value) => { ele.Transparency = (string)value; }
                }
            };
            return _sharedPropertyObservers;
        }

        public virtual SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2d point, bool forRef)
        {
            return null;
        }
    }
}
